/*
 * 版权所有 (C) 2015 知启蒙(ZHIQIM) 保留所有权利。[遇见知启蒙，邂逅框架梦]
 * 
 * https://zhiqim.org/project/zhiqim_framework/zhiqim_httpd.htm
 *
 * Zhiqim Httpd is licensed under Mulan PSL v2.
 * You can use this software according to the terms and conditions of the Mulan PSL v2.
 * You may obtain a copy of Mulan PSL v2 at:
 *          http://license.coscl.org.cn/MulanPSL2
 * THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND,
 * EITHER EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT,
 * MERCHANTABILITY OR FIT FOR A PARTICULAR PURPOSE.
 * See the Mulan PSL v2 for more details.
 */
package org.zhiqim.httpd.websocket;

import java.io.IOException;

import org.zhiqim.httpd.HttpConnection;
import org.zhiqim.httpd.HttpContext;
import org.zhiqim.httpd.HttpSession;
import org.zhiqim.httpd.HttpSessionManager;
import org.zhiqim.httpd.HttpSessionUser;
import org.zhiqim.kernel.model.maps.HashMapSS;
import org.zhiqim.kernel.websocket.WebSocketConstants;
import org.zhiqim.kernel.websocket.WebSocketPacket;


/**
 * Websocket连接抽象类
 *
 * @version v1.0.0 @author zouzhigang 2018-6-30 新建与整理
 */
public abstract class HttpWebSocketAbs implements HttpWebSocket, WebSocketConstants
{
    protected HttpContext context;
    protected HashMapSS headerMap;
    protected HashMapSS parameterMap;
    protected HttpWebSocketManager manager;
    protected String protocol;
    protected String sessionId;
    protected HttpWebSocketService service;
    protected volatile boolean isRunning;
    
    public HttpWebSocketAbs(HttpContext context, HashMapSS headerMap, HashMapSS parameterMap, String protocol, String sessionId, HttpWebSocketService service)
    {
        this.context = context;
        this.headerMap = headerMap;
        this.parameterMap = parameterMap;
        this.manager = context.getWebSocketManager();
        this.protocol = protocol;
        this.sessionId = sessionId;
        
        this.service = service;
    }
    
    /** 子类根据不同的结构提供不同的连接类 */
    public abstract HttpConnection getConnection();
    
    /***********************************************************************************/
    //打开&关闭
    /***********************************************************************************/
    
    @Override /** 开启，子类实现 */
    public abstract void open();
    
    @Override /** 正常关闭 */
    public void close(int code)
    {
        try
        {
            service.onClose(this, code);
        }
        finally
        {
            getWebSocketManager().remove(this);
        }
    }

    @Override /** 异常关闭 */
    public void exception(Throwable e)
    {
        try
        {
            service.onException(this, e);
        }
        finally
        {
            getWebSocketManager().remove(this);
        }
    }
    
    /** 检查是否需要回调 */
    public void doOpen()
    {//开启回调
        getWebSocketManager().add(this);
        service.onOpen(this);
    }
    
    /***********************************************************************************/
    //发送数据
    /***********************************************************************************/
    
    @Override
    public boolean sendText(String text)
    {
        HttpConnection conn = getConnection();
        if (conn == null || conn.isClosed())
            return false;
        
        return send(conn, new WebSocketPacket().setText(text).toPacket());
    }
    
    @Override
    public boolean sendPing()
    {
        HttpConnection conn = getConnection();
        if (conn == null || conn.isClosed())
            return false;
        
        return send(conn, new WebSocketPacket().setPing().toPacket());
    }
    
    @Override
    public boolean sendPong()
    {
        HttpConnection conn = getConnection();
        if (conn == null || conn.isClosed())
            return false;
        
        return send(conn, new WebSocketPacket().setPong().toPacket());
    }
    
    @Override
    public boolean sendClose(int code)
    {
        HttpConnection conn = getConnection();
        if (conn == null || conn.isClosed())
            return false;
        
        return send(conn, new WebSocketPacket().setClose(code).toPacket());
    }
    
    @Override
    public boolean sendBinary(byte[] binary)
    {
        HttpConnection conn = getConnection();
        if (conn == null || conn.isClosed())
            return false;
        
        return send(conn, new WebSocketPacket().setBinary(binary).toPacket());
    }
    
    /** 统一同步发送 */
    private boolean send(HttpConnection conn, byte[] data)
    {
        try
        {
            synchronized (conn)
            {
                conn.write(data, 0, data.length);
            }
            return true;
        }
        catch (IOException e)
        {
            exception(e);
            return false;
        }
    }
    
    /***********************************************************************************/
    //获取属性
    /***********************************************************************************/

    @Override
    public String getProtocol()
    {
        return protocol == null?_DEFAULT_WEB_SOCKET_PROTOCOL_:protocol;
    }
    
    @Override
    public HttpSessionManager getSessionManager()
    {
        return context.getSessionManager();
    }
    
    @Override
    public String getSessionId()
    {
        return sessionId;
    }
    
    @Override
    public HttpSession getSession()
    {
        return getSessionManager().getSession(sessionId);
    }
    
    @Override
    public HttpSessionUser getSessionUser()
    {
        HttpSession session = getSession();
        return session == null?null:session.getSessionUser();
    }
    
    @Override
    public HttpWebSocketService getWebSocketService()
    {
        return service;
    }
    
    @Override
    public HttpWebSocketManager getWebSocketManager()
    {
        return context.getWebSocketManager();
    }
    
    @Override
    public HashMapSS getHeaderMap()
    {
        return headerMap;
    }
    
    @Override
    public String getHeader(String name)
    {
        return headerMap.get(name);
    }
    
    @Override
    public HashMapSS getParameterMap()
    {
        return parameterMap;
    }
    
    @Override
    public String getParameter(String name)
    {
        return parameterMap.get(name);
    }
}
